/*
 * Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.love.cloud.common.security.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.love.cloud.admin.api.dto.UserInfo;
import com.love.cloud.admin.api.entity.SysRole;
import com.love.cloud.common.core.constant.DubboConstant;
import com.love.cloud.common.core.constant.SecurityConstants;
import com.love.cloud.common.security.service.MyUser;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 安全工具类
 *
 * @author L.cm
 */
@UtilityClass
public class SecurityUtils {

	private static TokenStore tokenStore;

	private TokenStore getTokenStore(){
		if (tokenStore==null) {
			tokenStore= SpringUtil.getBean(TokenStore.class);
		}
		return tokenStore;
	}

	/**
	 * 获取Authentication
	 */
	public Authentication getAuthentication() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication!=null) {
			return authentication;
		}else{
			try {
				//从dubbo中获取上下文信息
				if(RpcContext.getContext()!=null&&RpcContext.getContext().getAttachment(DubboConstant.ACCESS_TOKEN_KEY)!=null){
					String token = RpcContext.getContext().getAttachment(DubboConstant.ACCESS_TOKEN_KEY);
					if(StringUtils.isNotEmpty(token)){
						TokenStore tokenStore = getTokenStore();
						OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(token);
						return oAuth2Authentication;
					}
				}
			}catch (Exception ex){
				ex.printStackTrace();
				return null;
			}
		}
		return SecurityContextHolder.getContext().getAuthentication();
	}

	/**
	 * 获取用户
	 */
	public MyUser getUser(Authentication authentication) {
		Object principal = authentication.getPrincipal();
		if (principal instanceof MyUser) {
			return (MyUser) principal;
		}
		return null;
	}

	/**
	 * 获取用户
	 */
	public MyUser getUser() {
		Authentication authentication = getAuthentication();
		if (authentication == null) {
			return null;
		}
		return getUser(authentication);
	}


	/**
	 * 外部获取用户
	 */
	public UserInfo externalGetUser() {
		Authentication authentication = getAuthentication();
		if (authentication == null) {
			return null;
		}
		UserInfo userInfo=null;
		try {
			Map pageUser=(Map)authentication.getPrincipal();
			if(pageUser.get(SecurityConstants.DETAILS_USERINFO)!=null){
				userInfo = BeanUtil.mapToBean((Map) pageUser.get(SecurityConstants.DETAILS_USERINFO), UserInfo.class,false);
			}

		}catch (Exception e) {
			//登录状态过期
			e.printStackTrace();
		}
		return userInfo;
	}

	/**
	 * 获取用户角色信息
	 * @return 角色集合
	 */
	public List<Integer> getRoles() {
		Authentication authentication = getAuthentication();
		Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

		List<Integer> roleIds = new ArrayList<>();
		authorities.stream().filter(granted -> StrUtil.startWith(granted.getAuthority(), SecurityConstants.ROLE))
				.forEach(granted -> {
					String id = StrUtil.removePrefix(granted.getAuthority(), SecurityConstants.ROLE);
					roleIds.add(Integer.parseInt(id));
				});
		return roleIds;
	}

	/**
	 * 判断是否有某个角色
	 * @param role
	 * @return
	 */
	public boolean hasRolesByCode(String role) {
		if(getUser()!=null){
			List<SysRole> rolesList = getUser().getUserInfo().getRoles();
			if (rolesList != null) {
				for (SysRole sysRole: rolesList) {
					if (sysRole.getRoleCode().contains(role)) {
						return true;
					}
				}
			}
		}
		return false;
	}

}
